
/* Copyright (c) Mark J. Kilgard, 1996. */

/* This program is freely distributable without licensing fees
   and is provided without guarantee or warrantee expressed or
   implied. This program is -not- in the public domain. */

#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>

#define MAX_SPLATS 100

extern int logo_width;
extern int logo_height;
extern unsigned char logo_image[];

typedef struct _SplatInfo {
	int x, y;
	GLboolean alphaTest;
	GLfloat xScale, yScale;
	GLfloat scale[3];
	GLfloat bias[3];
} SplatInfo;

int winHeight;
int numSplats = 0;
SplatInfo splatConfig;
SplatInfo splatList[MAX_SPLATS];
SplatInfo splatDefault = {
	0, 0,
	GL_TRUE,
	1.0, 1.0,
	{1.0, 1.0, 1.0},
	{0.0, 0.0, 0.0},
};

void
reshape(int w, int h)
{
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, w, 0, h);
	glMatrixMode(GL_MODELVIEW);
	winHeight = h;
}

void
renderSplat(SplatInfo *splat)
{
	glRasterPos2i(splat->x, splat->y);
	if(splat->yScale >= 0)
		glBitmap(0, 0, 0, 0, 0, -logo_height * splat->yScale, 0);
	if(splat->xScale < 0)
		glBitmap(0, 0, 0, 0, logo_width * -splat->xScale, 0, 0);
	glPixelZoom(splat->xScale, splat->yScale);
	glPixelTransferf(GL_RED_SCALE, splat->scale[0]);
	glPixelTransferf(GL_GREEN_SCALE, splat->scale[1]);
	glPixelTransferf(GL_BLUE_SCALE, splat->scale[2]);
	glPixelTransferf(GL_RED_BIAS, splat->bias[0]);
	glPixelTransferf(GL_GREEN_BIAS, splat->bias[1]);
	glPixelTransferf(GL_BLUE_BIAS, splat->bias[2]);
	if (splat->alphaTest)
		glEnable(GL_ALPHA_TEST);
	else
		glDisable(GL_ALPHA_TEST);
	glDrawPixels(logo_width, logo_height, GL_RGBA,
	             GL_UNSIGNED_BYTE, logo_image);
}

void
display(void)
{
	int i;

	glClear(GL_COLOR_BUFFER_BIT);
	for (i = 0; i < numSplats; i++) {
		renderSplat(&splatList[i]);
	}
}

void
mouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON) {
		if (state == GLUT_DOWN) {
			if (numSplats < MAX_SPLATS) {
				splatConfig.x = x;
				splatConfig.y = winHeight - y;
				renderSplat(&splatConfig);
				splatList[numSplats] = splatConfig;
				numSplats++;
			} else {
				printf("out of splats!\n");
			}
		}
	}
}

void
mainSelect(int value)
{
	GLfloat rpos[4];
	GLboolean valid;

	switch(value) {
	case 0:
		numSplats = 0;
		glutPostRedisplay();
		break;
	case 1:
		splatConfig = splatDefault;
		break;
	case 2:
		splatConfig.xScale *= 1.25;
		splatConfig.yScale *= 1.25;
		break;
	case 3:
		splatConfig.xScale *= 0.75;
		splatConfig.yScale *= 0.75;
		break;
	case 4:
		splatConfig.xScale *= -1.0;
		break;
	case 5:
		splatConfig.yScale *= -1.0;
		break;
	case 6:
		splatConfig.alphaTest = GL_TRUE;
		break;
	case 7:
		splatConfig.alphaTest = GL_FALSE;
		break;
	case 411:
		glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
		glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
		printf("Raster position (%g,%g) is %s\n",
		       rpos[0], rpos[1], valid ? "valid" : "INVALID");
		break;
	case 666:
		exit(0);
		break;
	}
}

void
scaleBiasSelect(int value)
{
	int color = value >> 4;
	int option = value & 0xf;

	switch(option) {
	case 1:
		splatConfig.bias[color] += 0.25;
		break;
	case 2:
		splatConfig.bias[color] -= 0.25;
		break;
	case 3:
		splatConfig.scale[color] *= 2.0;
		break;
	case 4:
		splatConfig.scale[color] *= 0.75;
		break;
	}
}

int
glutScaleBiasMenu(int mask)
{
	int menu;

	menu = glutCreateMenu(scaleBiasSelect);
	glutAddMenuEntry("+25% bias", mask | 1);
	glutAddMenuEntry("-25% bias", mask | 2);
	glutAddMenuEntry("+25% scale", mask | 3);
	glutAddMenuEntry("-25% scale", mask | 4);
	return menu;
}

int
main(int argc, char *argv[])
{
	int mainMenu, redMenu, greenMenu, blueMenu;

	glutInitWindowSize(680, 440);
	glutInit(&argc, argv);
	splatConfig = splatDefault;

	glutCreateWindow("splatlogo");

	glutReshapeFunc(reshape);
	glutDisplayFunc(display);
	glutMouseFunc(mouse);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glAlphaFunc(GL_GEQUAL, 0.5);
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_DITHER);
	glClearColor(1.0, 1.0, 1.0, 0.0);

	redMenu = glutScaleBiasMenu(0 << 4);
	greenMenu = glutScaleBiasMenu(1 << 4);
	blueMenu = glutScaleBiasMenu(2 << 4);

	mainMenu = glutCreateMenu(mainSelect);
	glutAddMenuEntry("Reset splays", 0);
	glutAddMenuEntry("Reset splat config", 1);
	glutAddSubMenu("Red control", redMenu);
	glutAddSubMenu("Green control", greenMenu);
	glutAddSubMenu("Blue control", blueMenu);
	glutAddMenuEntry("+25% zoom", 2);
	glutAddMenuEntry("-25% zoom", 3);
	glutAddMenuEntry("X flip", 4);
	glutAddMenuEntry("Y flip", 5);
	glutAddMenuEntry("Enable alpha test", 6);
	glutAddMenuEntry("Disable alpha test", 7);
	glutSetMenu(mainMenu);
	glutAddMenuEntry("Query raster position", 411);
	glutAddMenuEntry("Quit", 666);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	glutMainLoop();
	return 0; /* Never reached; make ANSI C happy. */
}
